/* 
 * File:   Vector3.cpp
 * Author: brady
 * 
 * Created on June 6, 2011, 11:23 PM
 */

#include <core/Vector3D.h>

Vector3D& Vector3D::normalize()
{
  const double vector_length = sqrt( data[0]*data[0] +
				     data[1]*data[1] +
				     data[2]*data[2] );

  if (vector_length > 0.0) //dividing by zero isn't cool
    {
      data[0] /= vector_length;
      data[1] /= vector_length;
      data[2] /= vector_length;
    }

  return *this;
}

double Vector3D::dot(const Vector3D& v) const
{
    return  data[0]*v.data[0]
           +data[1]*v.data[1]
           +data[2]*v.data[2];
}

Vector3D Vector3D::cross(const Vector3D& v) const
{
    double x,y,z;
      x = data[1]*v.data[2] - data[2]*v.data[1];
      y = data[2]*v.data[0] - data[0]*v.data[2];
      z = data[0]*v.data[1] - data[1]*v.data[0];
      return Vector3D(x,y,z);
}

double Vector3D::magnitude() const {
    return sqrt(data[0] * data[0] +
                data[1] * data[1] +
                data[2] * data[2]);
}

Vector3D Vector3D::mix(const Vector3D& v) const{
    Vector3D final = Vector3D();
    final.data[0] = this->data[0]*v.data[0];
    final.data[1] = this->data[1]*v.data[1];
    final.data[2] = this->data[2]*v.data[2];
    return final;
}

Vector3D Vector3D::weightedAverage(const Vector3D& v, double weight) const {
    Vector3D final;
    double weightInv = 1.0-weight;
    final.data[0] = this->data[0]*weightInv + v.data[0]*weight;
    final.data[1] = this->data[1]*weightInv + v.data[1]*weight;
    final.data[2] = this->data[2]*weightInv + v.data[2]*weight;
    return final;
}

Vector3D& Vector3D::cap(double value){
    data[0] = min(data[0], value);
    data[1] = min(data[1], value);
    data[2] = min(data[2], value);
    return *this;
}

Vector3D Vector3D::bisect(const Vector3D& v) const{
    Vector3D bisector(*this);
    bisector += v;
    bisector.normalize();
    return bisector;
}

const string Vector3D::toString() const{
     ostringstream buff;
     buff<<"["<<data[0]<<"]["<<data[1]<<"]["<<data[2]<<"]";
     return buff.str();
}

const Vector3D operator+(const Vector3D &lhs, const Vector3D &rhs)
  {
    return Vector3D(lhs) += rhs;
  }
  const Vector3D operator-(const Vector3D &lhs, const Vector3D &rhs)
  {
    return Vector3D(lhs) -= rhs;
  }
  const Vector3D operator*(const Vector3D &lhs, const double rhs)
  {
    return Vector3D(lhs) *= rhs;
  }
  const Vector3D operator*(const double lhs, const Vector3D &rhs)
  {
    return Vector3D(rhs) *= lhs;
  }
  const Vector3D operator/(const Vector3D &lhs, const double rhs)
  {
    return Vector3D(lhs) /= rhs;
  }

bool operator<(const Vector3D& lhs, const Vector3D& rhs){
    return (lhs[0] < rhs[0] &&
            lhs[1] < rhs[1] &&
            lhs[2] < rhs[2]);
}
bool operator<=(const Vector3D& lhs, const Vector3D& rhs){
    return (lhs[0] <= rhs[0] &&
            lhs[1] <= rhs[1] &&
            lhs[2] <= rhs[2]);
    
}
bool operator>(const Vector3D& lhs, const Vector3D& rhs){
    return (lhs[0] > rhs[0] &&
            lhs[1] > rhs[1] &&
            lhs[2] > rhs[2]);
    
}
bool operator>=(const Vector3D& lhs, const Vector3D& rhs){
    return (lhs[0] >= rhs[0] &&
            lhs[1] >= rhs[1] &&
            lhs[2] >= rhs[2]);
}